package com.wu.service.impl;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wu.error.BusinessException;
import com.wu.error.EnumBusinessError;
import com.wu.mapper.*;
import com.wu.pojo.Articles;
import com.wu.pojo.Classify;
import com.wu.pojo.Labels;
import com.wu.pojo.model.ArticleModel;
import com.wu.pojo.model.DateYear;
import com.wu.pojo.model.UserToken;
import com.wu.service.ArticlesService;
import com.wu.util.*;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.wu.constant.Constant.*;

/**
 * @author: 吴磊
 * @program: blog
 * @create: 2021-04-19 20:35
 */
@Service
public class ArticlesServiceImpl extends ServiceImpl<ArticlesMapper, Articles> implements ArticlesService {
    @Autowired
    private MyUtil myUtil;

    @Autowired
    private ArticleConversionUtil articleConversionUtil;

    @Autowired
    private ArticlesMapper articlesMapper;

    @Autowired
    private ArticleDataUtil articleDataUtil;

    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private LabelsMapper labelsMapper;

    @Autowired
    private ArticleClassifyMapper articleClassifyMapper;

    @Autowired
    private TokenUtils tokenUtils;

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ArticleLabelMapper articleLabelMapper;

    @Autowired
    private CommentsMapper commentsMapper;

    @Autowired
    private ClassifyMapper classifyMapper;

    @Autowired
    private ArticleReportMapper articleReportMapper;

    @Autowired
    private CommentReportMapper commentReportMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private LuceneUtil luceneUtil;

    @Override
    public List<DateYear> getALlDate(String userId) {
        List<String> allDataDate = articlesMapper.getAllDataDate(userId);
        return articleDataUtil.getArticleDataClassify(allDataDate);
    }

    @Override
    public Integer getArticleCount(String userId) {
        if (StringUtils.isEmpty(userId)) {
            userId = null;
        }
        //articlesMapper.selectCount(Wrappers.<Articles>query().eq("user_id", userId));
        return articlesMapper.getArticleCount(userId);
    }

    @Override
    public Map<Object, Object> getArticleById(String articleId) {

        if (StringUtils.isEmpty(articleId)) {
            throw new BusinessException(EnumBusinessError.PARAMETER_INVALID_ERROR, "文章参数不能为空");
        }
        Map<Object, Object> map = new HashMap<>();
        ArticleModel articleModel = new ArticleModel();
        //1、先查询文章
        Articles article = articlesMapper.getArticleById(articleId);
        article.setArticleCommentCount(redisUtil.getStringValue(articleId, _COMMENT_COUNT));
        article.setArticleLikeCount(redisUtil.getStringValue(articleId, _ARTICLE_UP_COUNT));
        //5、添加文章的浏览量
        addView(articleId);
        article.setArticleViews(redisUtil.getArticleViews(articleId));
        BeanUtils.copyProperties(article, articleModel);
        //2、查询文章对应的类别
        Classify classify = articleClassifyMapper.getClassifyByArticle(articleId);
        articleModel.setClassify(classify);
        //3、查询文章对应的作者
        UserToken userToken = usersMapper.getUserTokenById(article.getUserId());
        articleModel.setUserToken(userToken);
        //添加一步：处理码龄
        String registrationTime = userToken.getUserRegistrationTime();
        long currentTimeMillis = System.currentTimeMillis();
        long time = currentTimeMillis - myUtil.parseTimeToString(registrationTime);
        long how = time / 1000 / 60 / 60 / 24 / 30 / 12 + 1;
        map.put(REGISTRATION_TIME, how);
        //4、查询文章对应的标签
        List<Labels> labels = labelsMapper.getLabelByArticleId(articleId);
        articleModel.setLabels(labels);
        map.put(ARTICLE, articleModel);
        //处理是否是自己的文章
        if (!StringUtils.isEmpty(tokenUtils.parseTokenToken())) {
            //登录了，但不清楚是不是自己
            UserToken token = tokenUtils.parseTokenToUserToken();
            String userId = token.getUserId();
            //看下是否点赞
            Boolean isLike = redisTemplate.opsForSet().isMember(userId + _ARTICLE_UP, articleId);
            if (Boolean.FALSE.equals(isLike)) {
                map.put(LIKE, false);
            } else {
                map.put(LIKE, true);
            }
            //看下是否收藏
            Boolean isCollect = redisTemplate.opsForSet().isMember(userId + _COLLECT, articleId);
            if (isCollect) {
                map.put(COLLECT, true);
            } else {
                map.put(COLLECT, false);
            }
            //是否关注这个博主
            Boolean isFriend = redisTemplate.opsForSet().isMember(userId + _FOCUS, article.getUserId());
            if (!isFriend) {
                map.put(IS_FRIEND, false);
            } else {
                map.put(IS_FRIEND, true);
            }
            if (!userId.equals(article.getUserId())) {
                map.put(OWNER, false);
            } else {
                map.put(OWNER, true);
                map.put(IS_FRIEND, true);
            }
        } else {
            //游客访问
            map.put(IS_FRIEND, false);
            map.put(LIKE, false);
            map.put(OWNER, false);
            map.put(COLLECT, false);
        }
        return map;
    }


    @Override
    public void addView(String articleId) {
        //先判断是否为游客浏览
        String login = tokenUtils.parseTokenToken();
        if (!StringUtils.isEmpty(login)) {
            UserToken userToken = tokenUtils.getInfoFromToken(login);
            String userId = userToken.getUserId();
            String viewToken = login + articleId;
            if (!redisUtil.hasKey(viewToken)) {
                redisUtil.set(viewToken, articleId, 30);
                redisTemplate.opsForZSet().incrementScore(ARTICLE_VIEWS, articleId, 1);
                redisTemplate.opsForValue().increment(userId + _ARTICLE_VIEWS_COUNT);
            }
        }
    }

    @Override
    public HashMap<String, Object> getArticleBySomeThing(String classify, String p, String userId, String articleWay) {
        boolean flag = true;
        int curpage = Integer.parseInt(p);
        HashMap<String, Object> map2 = new HashMap<>();
        //总篇数
        int total = 0;
        //如果用户ID不为空就返回全部文章
        if (!StringUtils.isEmpty(userId)) {
            map2.put(USER_ID, userId);
        }
        //返回的文章结果集
        List<Articles> articles;
        if (!StringUtils.isEmpty(articleWay)) {
            map2.put(ARTICLE_WAY, articleWay);
        }
        if (myUtil.isInteger(classify.substring(0, classify.indexOf('-') == -1 ? 1 : classify.indexOf('-')))) {  //日期
            map2.put(ARTICLE_DATE, classify);
            total = articlesMapper.getArticleCountByArticleDate(map2);
            flag = false;
        } else { //文章分类
            List<String> articleIds = articleClassifyMapper.getArticleIdByClassify(classify);
            if (articleIds != null && articleIds.size() > 0) {
                ArrayList<String> ids = new ArrayList<>();
                int len = articleIds.size();
                total = len;
                flag = false;
                for (int i = 0; i < len; i++) {
                    ids.add(articleIds.get(i));
                }
                map2.put(ARTICLE_IDS, ids);
            }
        }
        if (flag) {
            total = articlesMapper.getArticleCount(userId);
        }
        int totalPage = (total + 10 - 1) / 10;
        if (totalPage == 0) {
            //总篇数
            map2.put(TOTAL, 0);
            //总页数
            map2.put(PAGES, 0);
            //文章 <=10篇
            map2.put(ARTICLES, new ArrayList<>());
            return map2;
        }
        if (curpage < 1) {
            curpage = 1;
        }
        if (curpage > totalPage) {
            curpage = totalPage;
        }
        map2.put(CURPAGE, (curpage - 1) * 10);
        articles = articlesMapper.getArticleBySomeThing(map2);
        articles = articleConversionUtil.getArticleByOther(articles);
        HashMap<String, Object> map = new HashMap<>();
        List<ArticleModel> articleModels;
        String isLogin = tokenUtils.parseTokenToken();
        if (StringUtils.isEmpty(isLogin)) {
            //没有登录
            articleModels = articles.stream().map(article -> {
                ArticleModel articleModel = returnArticleModel(article);
                map.put(articleModel.getArticleId(), false);
                return articleModel;
            }).collect(Collectors.toList());
        } else {
            //登录了
            UserToken token = tokenUtils.getInfoFromToken(isLogin);
            String loginUserId = token.getUserId();
            articleModels = articles.stream().map(article -> {
                String articleId = article.getArticleId();
                ArticleModel articleModel = returnArticleModel(article);
                Boolean isLike = redisTemplate.opsForSet().isMember(loginUserId + _ARTICLE_UP, articleId);
                if (Boolean.FALSE.equals(isLike)) {
                    map.put(articleId, false);
                } else {
                    map.put(articleId, true);
                }
                return articleModel;
            }).collect(Collectors.toList());
        }
        //总篇数
        map.put(TOTAL, total);
        //总页数
        map.put(PAGES, totalPage);
        //文章 <=10篇
        map.put(ARTICLES, articleModels);
        return map;
    }

    private ArticleModel returnArticleModel(Articles article) {
        String articleId = article.getArticleId();
        UserToken userToken = usersMapper.getUserTokenById(article.getUserId());
        ArticleModel articleModel = new ArticleModel();
        article.setArticleCommentCount(redisUtil.getStringValue(articleId, _COMMENT_COUNT));
        article.setArticleLikeCount(redisUtil.getStringValue(articleId, _ARTICLE_UP_COUNT));
        article.setArticleViews(redisUtil.getArticleViews(articleId));
        BeanUtils.copyProperties(article, articleModel);
        articleModel.setUserToken(userToken);
        return articleModel;
    }


    @Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            timeout = 100,
            noRollbackForClassName = {"RunTimeException"}
    )
    @Override
    public String insertArticle(String articleTitle, String articleContent, String classifyId, String labelNames, String articleWay, String diyClassify) {
        //1、获取当前登录用户ID
        UserToken userToken = tokenUtils.parseTokenToUserToken();
        String userId = userToken.getUserId();
        String articleId = IdWorker.get32UUID();
        String currentTime = myUtil.getCurrentDetailedTime();
        //2、插入文章
        Integer integer = articlesMapper.insertArticle(articleId, userId, articleTitle, articleContent, currentTime, articleWay);
        redisTemplate.opsForZSet().add(ARTICLE_VIEWS, articleId, 0);
        if (integer <= 0) {
            throw new BusinessException(EnumBusinessError.UNKNOWN_ERROR, "文章插入失败，请联系管理员");
        }
        //3、插入分类
        Integer insert = 0;
        diyClassify = diyClassify.trim();
        if (StringUtils.isEmpty(diyClassify)) {
            //如果用户没有自定义分类，那肯定选择的是已存在的分类
            insert = articleClassifyMapper.insert(articleId, classifyId);
        } else {
            //不为空，传的是数据库里面没有的
            //先查询数据库是否已存在自定义分类
            Classify diyIfy = classifyMapper.getClassifyByName(diyClassify);
            if (diyIfy != null) {
                //说明数据库存在自定义的分类
                insert = articleClassifyMapper.insert(articleId, diyIfy.getClassifyId());
            } else {
                //数据库中不存在自定义分类
                //1、先插入自定义分类：
                String diyId = IdWorker.get32UUID();
                classifyMapper.addClassify(diyId, diyClassify);
                //2、再插入即可
                insert = articleClassifyMapper.insert(articleId, diyId);
            }
        }
        if (insert <= 0) {
            throw new BusinessException(EnumBusinessError.UNKNOWN_ERROR, "文章插入失败，请联系管理员");
        }
        //4、插入标签
        insertLabel(labelNames, articleId);
        myUtil.checkLevel(userId);
        //5、创建索引
        Articles articles = new Articles();
        articles.setArticleId(articleId);
        articles.setUserId(userId);
        articles.setArticleContent(articleContent);
        articles.setArticleDate(currentTime);
        articles.setArticleWay(articleWay);
        articles.setArticleTitle(articleTitle);
        luceneUtil.createIndex(articleConversionUtil.getArticleByOther100(articles));
        return articleId;
    }

    private void insertLabel(String labelNames, String articleId) {
        if (!StringUtils.isEmpty(labelNames)) {
            String[] split = labelNames.split("=");
            for (int i = 0; i < split.length; i++) {
                String trim = split[i].trim();
                Integer insert1 = 0;
                if (!StringUtils.isEmpty(trim)) {
                    //1、先查询此分段是否是数据库中已经存在的
                    String lableId = labelsMapper.getIdByLabelName(trim);
                    if (StringUtils.isEmpty(lableId)) {
                        //3、不存在就生成一个标签，并插入数据库，最后插入文章标签
                        String diyId = IdWorker.get32UUID();
                        Labels labels = new Labels();
                        labels.setLabelId(diyId);
                        labels.setLabelName(trim);
                        labelsMapper.insert(labels);
                        insert1 = articleLabelMapper.insert(articleId, diyId);
                    }
                    //2、如果存在就查出此标签Id即可
                    else {
                        insert1 = articleLabelMapper.insert(articleId, lableId);
                    }
                    if (insert1 <= 0) {
                        throw new BusinessException(EnumBusinessError.UNKNOWN_ERROR, "文章插入失败，请联系管理员");
                    }
                }
            }
        }
    }

    @Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            readOnly = false,
            timeout = 100,
            noRollbackForClassName = {"RunTimeException"}
    )
    @Override
    public String updateArticle(String articleId, String articleTitle, String articleContent, String classifyId, String labelNames, String articleWay, String diyClassify) {

        String currentTime = myUtil.getCurrentDetailedTime();
        //2、修改文章
        Integer integer = articlesMapper.updateArticle(articleId, articleTitle, articleContent, currentTime, articleWay);
        if (integer <= 0) {
            throw new BusinessException(EnumBusinessError.UNKNOWN_ERROR, "文章修改失败，请联系管理员");
        }
        String userId = tokenUtils.parseTokenToken();
        //修改索引
        Articles articles = new Articles();
        articles.setArticleId(articleId);
        articles.setUserId(userId);
        articles.setArticleContent(articleContent);
        articles.setArticleDate(currentTime);
        articles.setArticleWay(articleWay);
        articles.setArticleTitle(articleTitle);
        luceneUtil.updateIndex(articleConversionUtil.getArticleByOther(articles));

        //3、修改分类
        Integer insert;
        diyClassify = diyClassify.trim();
        if (StringUtils.isEmpty(diyClassify)) {
            //如果用户没有自定义分类，那肯定选择的是已存在的分类
            insert = articleClassifyMapper.update(articleId, classifyId);
        } else {
            //不为空，传的是数据库里面没有的

            //先查询数据库是否已存在自定义分类
            Classify diyIfy = classifyMapper.getClassifyByName(diyClassify);
            if (diyIfy != null) {
                //说明数据库存在自定义的分类
                insert = articleClassifyMapper.update(articleId, diyIfy.getClassifyId());
            } else {
                //数据库中不存在自定义分类
                //1、先插入自定义分类：
                String diyId = IdWorker.get32UUID();
                classifyMapper.addClassify(diyId, diyClassify);
                //2、再插入即可
                insert = articleClassifyMapper.update(articleId, diyId);
            }
        }
        if (insert <= 0) {
            throw new BusinessException(EnumBusinessError.UNKNOWN_ERROR, "文章修改失败，请联系管理员");
        }
        //4、删除标签
        try {
            articleLabelMapper.delete(articleId);
        } catch (Exception e) {
            throw new BusinessException(EnumBusinessError.UNKNOWN_ERROR, "文章修改失败，请联系管理员");
        }
        //4、插入标签
        insertLabel(labelNames, articleId);
        return articleId;
    }

    @Override
    public void addArticleComments(String articleId) {
        if (StringUtils.isEmpty(articleId)) {
            throw new BusinessException(EnumBusinessError.PARAMETER_INVALID_ERROR);
        }
        redisTemplate.opsForValue().increment(articleId + _COMMENT_COUNT);
    }

    @Override
    @Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            readOnly = false,
            timeout = 100,
            noRollbackForClassName = {"RunTimeException"}
    )
    public void deleteArticleByArticleId(String articleId) {
        //先直接删除文章索引
        luceneUtil.deleteIndex(articleId);
        UserToken userToken = tokenUtils.parseTokenToUserToken();
        String userId = userToken.getUserId();
        //1、先删除文章
        articlesMapper.deleteById(articleId);
        //2、删除与文章有关的标签
        articleLabelMapper.delete(articleId);
        //3、删除与文章有关的分类
        articleClassifyMapper.deleteByArticleId(articleId);
        //7、删除评论举报
        commentReportMapper.deleteCommentByArticleId(articleId);
        //8、删除所有的文章举报
        articleReportMapper.deleteReportByArticleId(articleId);
        //删除文章点赞数
        redisTemplate.opsForValue().decrement(userId + _UP_COUNT, redisUtil.getStringValue(articleId, _ARTICLE_UP_COUNT));
        redisTemplate.delete(articleId + _ARTICLE_UP_COUNT);
        // 删除用户点赞过的文章
        Set<Object> userIdSet = redisTemplate.opsForSet().members(articleId + _ARTICLE_UP_USER);
        Iterator<Object> it = userIdSet.stream().iterator();
        while (it.hasNext()) {
            String userId1 = (String) it.next();
            redisTemplate.opsForSet().remove(userId1 + _ARTICLE_UP, articleId);
        }
        redisTemplate.opsForValue().decrement(userId + _COMMENT_COUNT, redisUtil.getStringValue(articleId, _COMMENT_COUNT));
        redisTemplate.delete(articleId + _COMMENT_COUNT);  //删除文章评论数
        redisTemplate.opsForValue().decrement(userId + _ARTICLE_VIEWS_COUNT, redisUtil.getArticleViews(articleId));
        redisTemplate.opsForZSet().remove(ARTICLE_VIEWS, articleId);//删除文章浏览数
        redisTemplate.opsForValue().decrement(userId + _COLLECT_COUNT, redisUtil.getStringValue(articleId, _COLLECT_COUNT));
        redisTemplate.delete(articleId + _COLLECT_COUNT); //删除文章收藏数
        //删除用户收藏的文章
        Set<Object> userIdSet2 = redisTemplate.opsForSet().members(articleId + _COLLECT_USER);
        Iterator<Object> it2 = userIdSet2.stream().iterator();
        while (it2.hasNext()) {
            String userId2 = (String) it2.next();
            redisTemplate.opsForSet().remove(userId2 + _COLLECT, articleId);
        }
        //4、删除与文章有关的评论
        commentsMapper.deleteByArticleId(articleId);
        //5、刷新用户等级
        myUtil.checkLevel(userId);
    }

    @Override
    public List<String> getOwnerArticleId() {
        UserToken userToken = tokenUtils.parseTokenToUserToken();
        String userId = userToken.getUserId();
        return articlesMapper.getOwnerArticleId(userId);
    }

    @Override
    public Map<String, Object> getRecommend() {
        Map<String, Object> map = new HashMap<>();
        List<Articles> articlesMapperRecommend = articlesMapper.getRecommend();
        map.put(ARTICLES, articlesMapperRecommend);
        return map;
    }

    @Override
    public Map<String, Object> getRecommendByUserId(String userId) {
        if (userId == null) {
            throw new BusinessException(EnumBusinessError.PARAMETER_INVALID_ERROR, "获取用户今日推荐的时候，用户ID不能为空");
        }
        List<Articles> recommends = articlesMapper.getRecommendByUserId(userId);
        recommends = recommends.stream().peek(article -> article.setArticleViews(redisUtil.getArticleViews(article.getArticleId()))).collect(Collectors.toList());
        Map<String, Object> map = new HashMap<>();
        map.put(ARTICLES, articleSorted(recommends));
        return map;
    }


    /**
     * 文章自定义排序-
     *
     * @param articles
     * @return
     */
    @SneakyThrows
    private List<Articles> articleSorted(List<Articles> articles) {
        articles.sort((article1, article2) -> {
            if (article1.getArticleViews() > article2.getArticleViews()) {
                return 1;
            }
            if (article1.getArticleViews().equals(article2.getArticleViews())) {
                return 0;
            }
            return -1;
        });
        return articles;
    }


}
